/******************************************************************************
 * Project:		Packet Sniffer
 * Author:		Jonathan Buttner
 * Date:		1.15.2010
 * 
 * This file will hold all the execution code for any commands
 * that the program will execute.
 *****************************************************************************/

/******************************************************************************
 * Copyright (c) 1999 - 2005 NetGroup, Politecnico di Torino (Italy)
 * Copyright (c) 2005 - 2006 CACE Technologies, Davis (California)
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution.
 * 3. Neither the name of the Politecnico di Torino, CACE Technologies 
 * nor the names of its contributors may be used to endorse or promote 
 * products derived from this software without specific prior written 
 * permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 *****************************************************************************/

#include "Commands.h"
#include "pthread.h" /* Microsoft's incredible compiler isn't complient with the standered pthreads.h so got my own */
#include <assert.h>
#include <string.h>
#include <stdlib.h>
//#include <stdbool.h> LAME

/******************************************************************************
 *									FUNCTIONS
 *****************************************************************************/
/******************************************************************************
 * initCmd() allocates space for each command and assigns its function
 *
 * Post:
 *	space allocated for each function and functions assigned
 *
 *****************************************************************************/
void initCmd()
{
	/* NOTE TO SELF MICROSOFT IS WAY LAME
	 * ALL AND I MEAN *ALL* VARIABLES MUST BE
	 * DECLARED AT THE TOP OF THE FUNCTION...
	 */
	char stopCmdName[] = "stoplis";
	char listenCmdName[] = "listen";

	Stop = (Command*)malloc( sizeof(Command) );
	Listen = (Command*)malloc( sizeof(Command) );

	assert( Stop != NULL );
	assert( Listen != NULL );
	
	//Stop->name = "stoplis";
	
	strcpy( Stop->name, stopCmdName ); /* I get a unsafe warning for using strcpy consider using _s */
	Stop->execute = exeStoplis;

	//Listen->name = "listen";
	strcpy( Listen->name, listenCmdName );
	Listen->execute = exeListen;
}

/******************************************************************************
 * destCmd() destructs the allocated Commands.
 *
 * Post:
 *	the allocated memory is freed
 *
 *****************************************************************************/
void destCmd()
{
	if ( Stop )
		free( Stop );
	if ( Listen )
		free( Listen );
}

/******************************************************************************
 * exeStoplis() stops any current listening of packets
 *
 * Pre:
 *	packetCap points to a packet capture, it will be passed along to
 *	pcap_breakloop
 * Post:
 *	ends any listening of packets
 * Return:
 *	returns an Error message
 *
 *****************************************************************************/
Error exeStoplis( void *packetCap, void *NOTUSED, void* NOTUSEDPARM )
{
	stopLis( (pcap_t *) packetCap );
	return OK;
}

static void stopLis( pcap_t *pCap )
{
	pcap_breakloop( pCap );
}

/******************************************************************************
 * exeListen() listens to packets
 *
 * Members:
 *	device is the user chosen device to connect to
 *	numPackets is the number of packets to read, -1 is an interrupterable loop
 * Return:
 *	returns an Error message
 *
 *****************************************************************************/
Error exeListen( void *dev, void *nPak, void *packCap )
{
	return listenPak( (pcap_if_t*) dev, *((int *)nPak), (pcap_t**)packCap );
}

/* Callback function invoked by libpcap for every incoming packet */
static void packet_handler(
						   u_char *param,
						   const struct pcap_pkthdr *header,
						   const u_char *pkt_data )
{
    struct tm ltime;
    char timestr[16];
    time_t local_tv_sec;

    /*
     * unused variables
     */
    (VOID)(param);
    (VOID)(pkt_data);

    /* convert the timestamp to readable format */
    local_tv_sec = header->ts.tv_sec;
    localtime_s(&ltime, &local_tv_sec);
    strftime( timestr, sizeof timestr, "%H:%M:%S", &ltime);
    
    printf("%s,%.6d len:%d\n", timestr, header->ts.tv_usec, header->len);
}

/******************************************************************************
 * listenPak() is the lower level function that uses the actual needed params
 *
 * Members:
 *	device is the user chosen device to connect to
 *	numPackets is the number of packets to read, -1 is an interrupterable loop
 *  handle is a pointer to a pcap_t that will return the structure so that I
 *  can end the loop if stoplis is called
 * Pre:
 *  handle points to a structure managed by the caller that enables me to
 *  stop the listening
 * Post:
 *  handle will point to the allocated structure given by pcap_open()	
 * Return:
 *	returns an Error message
 *
 *****************************************************************************/
static Error listenPak( pcap_if_t *device, int numPackets, pcap_t **handle )
{
	pcap_t *adhandle;
	char errbuf[PCAP_ERRBUF_SIZE];
	
	struct tm ltime;
	char timestr[16];
	struct pcap_pkthdr *header;
	const u_char *pkt_data;
	time_t local_tv_sec;
	int res;

	/* Open the device */
    if ( (adhandle= pcap_open(device->name,     // name of the device
                              65536,            // portion of the packet to capture
                                                // 65536 guarantees that the whole packet will be captured on all the link layers
                              PCAP_OPENFLAG_PROMISCUOUS,    // promiscuous mode
                              100,             // read timeout
                              NULL,             // authentication on the remote machine
                              errbuf            // error buffer
                              ) ) == NULL)
    {
        fprintf(stderr,"\nUnable to open the adapter. %s is not supported by WinPcap\n", device->name);
        pcap_freealldevs(device);
		return NOTOK;
    }
	
	//pcap_freealldevs(device);
	printf("\nlistening on %s...\n", device->description);

	/* start the capture */
    //pcap_loop(adhandle, 0, packet_handler, NULL);
	while((res = pcap_next_ex( adhandle, &header, &pkt_data)) >= 0)
	{
        if(res == 0)
            continue;
        
        local_tv_sec = header->ts.tv_sec;
        localtime_s(&ltime, &local_tv_sec);
        strftime( timestr, sizeof timestr, "%H:%M:%S", &ltime);
        
        printf("%s,%.6d len:%d\n", timestr, header->ts.tv_usec, header->len);
    }
    
    if(res == -1)
	{
        printf("Error reading the packets: %s\n", pcap_geterr(adhandle));
        return -1;
    }


	*handle = adhandle;
	return OK;
}

/******************************************************************************
 * createLisThread() will take care of creating the thread that will run
 * the loop that will listen and capture packets.
 *
 * Members:
 *	device is the user chosen device to connect to
 *	numPackets is the number of packets to read, -1 is an interrupterable loop
 *  handle is a pointer to a pcap_t that will return the structure so that I
 *  can end the loop if stoplis is called
 * Pre:
 *  handle points to a structure managed by the caller that enables me to
 *  stop the listening
 * Post:
 *  handle will point to the allocated structure given by pcap_open()	
 * Return:
 *	returns an Error message
 * 
 *****************************************************************************/
static Error createLisThread(
					  pcap_if_t *device,
					  int numPak,
					  pcap_t **handle )
{
	int rc = 0;
	pthread_t listThread;
	ListenCmd listCmd;
}

/******************************************************************************
 * *runLisThread() will be passed to the pthread_create() function and will
 * detail what the thread actually executes.
 *
 * Members:
 *	threadId is the ID of the thread.
 * 
 *****************************************************************************/
static void *runLisThread( void *threadId )
{
	
}

/******************************************************************************
 * cleanupHandler() will take care of exiting the capture loop by setting
 * a flag to false
 *
 * Members:
 *	arg is any info that the handler needs to know, it is NOT USED
 * 
 *****************************************************************************/
static void cleanupHandler( void *arg )
{

}